# -*- coding: utf-8 -*-
"""
:Author: Fernando Pacheco <fernando.pacheco@ingesur.com.uy>
:Date: Fri, 12 Jun 2009 19:29:27 -0300
:copyright: Ingesur SRL
:license: GPL Version 2
:todo: Must complete missing functions
:warning: Esta es el warning
:bug: Este es el bug
"""
from wellfunctions import *
from scipy.optimize import fsolve
import math


class VWellPR(WellFunctions):
    """
    Base class for calculations in verticals wells in permanent regime

    Works with confined, semiconfined and unconfined aquifers
    """

    def __init__(self):
        WellFunctions.__init__(self)


    def dropdown_unconfined_aquifer(self, Ho, flow_rate, hydraulic_cond, observation_distance, inf_radius):
        """
        Dropdown calculations in unconfined aquifers

            :Parameters:
                Ho : float
                  Nivel inicial de agua en el acuífero.
                flow_rate : float
                  Caudal de extracción (por ejemplo en m3/h).
                hydraulic_cond : float
                  Conductividad hidráulica en unidades homogéneas ( en este ejemplo en m/h).
                observation_distance : float
                  Distancia desde centro de bombeo donde se desea encontrar el descenso.
                inf_radius : float
                  Radio de influencia.

            :rtype: float
            :return: Dropdown in unconfined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.dropdown_unconfined_aquifer(30.0,240.00,10,2.0,500.0)
            >>> print ("%.5f" % dd )
            0.71145

        """
        hf = self.sqrt( Ho*Ho - flow_rate*self.Ln(inf_radius/observation_distance)/( 2*self.pi()*hydraulic_cond) )
        """:var hf: Prueba"""
        return ( Ho - hf )

    def dropdown_semiconfined_aquifer(self, well_radius, observation_distance, flow_rate, transmisivity, B, kp=None,  bp=None):
        """
        Dropdown calculations in unconfined aquifers

            :Parameters:
                well_radius : float
                  Radio del pozo de bombeo ( en este ejemplo en m).
                flow_rate : float
                  Caudal de extraccion (por ejemplo en m3/h).
                transmisivity : float
                  Transmisividad hidraulica en unidades homogeneas ( en este ejemplo en m2/h).
                B : float
                  Coeficiente de goteo.
                kp : float
                  Conductividad hidraulica del acuitardo en unidades homogeneas ( en este ejemplo en m/h).
                bp : float
                  Espesor del acuitardo en unidades homogeneas ( en este ejemplo en m).
                observation_distance : float
                  Distancia desde centro de bombeo donde se desea encontrar el descenso en unidades homogeneas ( en este ejemplo en m).

            :rtype: float
            :return: Dropdown in semiconfined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.dropdown_semiconfined_aquifer(0.5,100.00,250.0,100.0,100.0)
            >>> print ("%.3f" % dd )
            0.168

        """
        return ( flow_rate*self.k0(observation_distance/B)/( 2*self.pi()*transmisivity*well_radius/B*self.k1(well_radius/B) ) )

    def dropdown_confined_aquifer(self, flow_rate, transmisivity,  observation_distance,  inf_radius):
        """
        Calculo de descenso en acuíferos confinados

            :Parameters:

                flow_rate : float
                  Caudal de extraccion (por ejemplo en m3/h).
                transmisivity : float
                  Transmisividad hidraulica en unidades homogeneas ( en este ejemplo en m2/h).
                observation_distance : float
                  Distancia desde centro de bombeo donde se desea encontrar el descenso en unidades homogeneas ( en este ejemplo en m).
                inf_radius : float
                  Radio de influencia.

            :rtype: float
            :return: Dropdown in confined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.dropdown_confined_aquifer(250.0,100.00,0.5,800.0)
            >>> print ("%.3f" % dd )
            1.468

        """
        return ( flow_rate*self.Ln(inf_radius/observation_distance)/( 4*self.pi()*transmisivity) )

    def hydraulic_conductivity_unconfined_aquifer(self, Ho, flow_rate, dropdown, observation_distance, inf_radius):
        """
        :Parameters:

                flow_rate : float
                  Caudal de extraccion (por ejemplo en m3/h).
                dropwdown : float
                  Caudal de extraccion (por ejemplo en m3/h).
                observation_distance : float
                  Distancia desde centro de bombeo donde se desea encontrar el descenso en unidades homogeneas ( en este ejemplo en m).
                inf_radius : float
                  Radio de influencia.

            :rtype: float
            :return: Hydraulic Conductivity in unconfined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.hydraulic_conductivity_unconfined_aquifer(10.0,250.0,3.0,0.5,800.0)
            >>> print ("%.3f" % dd )
            5.756
        """
        h = (Ho-dropdown)
        return ( flow_rate*self.Ln(inf_radius/observation_distance)/(2*self.pi()*(Ho*Ho-h*h)) )

    def aux_fun_tsa(self,x,a,rp,obs,bb):
        """
        Auxiliar function to calculate observation_distance_semiconfined
        """
        # print "x = %f, a = %f, rp = %f, obs = %f, bb = %f" % (x,a,rp,obs,bb)
        return ( a*self.k1(rp/math.sqrt(bb*x))*x-math.sqrt(x)*self.k0(obs/math.sqrt(bb*x)) )

    def transmisivity_semiconfined_aquifer(self, well_radius, observation_distance, flow_rate, dropdown, kp, bp):
        """
        :Parameters:

                well_radius : float
                  Radio del poso ( en este ejemplo en m).
                observation_distance : float
                  Radio de observacion ( en este ejemplo en m).
                flow_rate : float
                  Caudal de extraccion (por ejemplo en m3/h).
                dropdown : float
                  Descenso en unidades homogeneas ( en este ejemplo en m).
                B : float
                  Factor Goteo ( en este ejemplo en m).

            :rtype: float
            :return: Transmisivity in unconfined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.hydraulic_conductivity_unconfined_aquifer(10.0,250.0,3.0,0.5,800.0)
            >>> print ("%.3f" % dd )
            5.756
        """
        # Initial transmisivity
        init_trans = 500 # 500 m2/d
        # kp m/d, flow_rate m3/d
        bb = bp/(1.0*kp)
        aa = 2.0*self.pi()*dropdown*well_radius/flow_rate*math.sqrt(kp/bp)
        trans_calc = fsolve(self.aux_fun_tsa,init_trans,args = (aa,well_radius,observation_distance,bb))
        return ( trans_calc )

    def transmisivity_confined_aquifer(self, flow_rate, dropdown,  observation_distance,  inf_radius):
        """
        Calculo de transmisividad en acuíferos confinados

            :Parameters:
                flow_rate : float
                  Caudal de extraccion (por ejemplo en m3/h).
                dropdown : float
                  Descenso en unidades homogeneas ( en este ejemplo en m).
                observation_distance : float
                  Distancia desde centro de bombeo donde se desea encontrar el descenso en unidades homogeneas ( en este ejemplo en m).
                inf_radius : float
                  Radio de influencia.

            :rtype: float
            :return: Transmisivity in confined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.transmisivity_confined_aquifer(250.0,1.0,0.5,1000.0)
            >>> print ("%.3f" % dd )
            151.215

        """
        return ( flow_rate*self.Ln(inf_radius/observation_distance)/( 4*self.pi()*dropdown) )

    def flow_rate_unconfined_aquifer(self, Ho, hydraulic_conductivity, dropdown, observation_distance, inf_radius):
        """
        Calculo de caudal en acuíferos libres

            :Parameters:
                Ho : float
                  Altura inicial ( en este ejemplo en m).
                hydraulic_conductivity : float
                  Conductividad Hidraulica (por ejemplo en m/d).
                dropdown : float
                  Descenso en unidades homogeneas ( en este ejemplo en m).
                observation_distance : float
                  Distancia desde centro de bombeo donde se desea encontrar el descenso en unidades homogeneas ( en este ejemplo en m).
                inf_radius : float
                  Radio de influencia.

            :rtype: float
            :return: Flow Rate in unconfined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.flow_rate_unconfined_aquifer(10.0,6.0,3.0,0.5,800.0)
            >>> print ("%.3f" % dd )
            260.601

        """
        h = (Ho-dropdown)
        return ( 2*self.pi()*hydraulic_conductivity*(Ho*Ho-h*h) / (self.Ln(inf_radius/observation_distance)) )

    def flow_rate_semiconfined_aquifer(self, well_radius, observation_distance, transmisivity, dropdown, B, kp=None,  bp=None):
        """
        Calculo de caudal en acuíferos semi confinados

            :Parameters:
                well_radius : float
                  Radio del poso ( en este ejemplo en m).
                observation_distance : float
                  Radio de observacion ( en este ejemplo en m).
                transmisivity : float
                  Transmisividad hidraulica en unidades homogeneas ( en este ejemplo en m2/h).
                dropdown : float
                  Descenso en unidades homogeneas ( en este ejemplo en m).
                B : float
                  Factor Goteo ( en este ejemplo en m).

            :rtype: float
            :return: Flow Rate in unconfined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.flow_rate_semiconfined_aquifer(0.5,100.0,100.0,0.5,100.0)
            >>> print ("%.3f" % dd )
            746.123

        """
        return ( 2*self.pi()*transmisivity*well_radius/B*self.k1(well_radius/B) * dropdown / (self.k0(observation_distance/B) ) )

    def flow_rate_confined_aquifer(self, transmisivity, dropdown,  observation_distance,  inf_radius):
        """
        Calculo de transmisividad en acuíferos confinados

            :Parameters:
                transmisivity : float
                  Transmisividad hidraulica en unidades homogeneas ( en este ejemplo en m2/h).
                dropdown : float
                  Descenso en unidades homogeneas ( en este ejemplo en m).
                observation_distance : float
                  Distancia desde centro de bombeo donde se desea encontrar el descenso en unidades homogeneas ( en este ejemplo en m).
                inf_radius : float
                  Radio de influencia.

            :rtype: float
            :return: Flowrate in confined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.flow_rate_confined_aquifer(100.0,1.0,0.5,100.0)
            >>> print ("%.3f" % dd )
            165.327

        """
        return ( dropdown*4*self.pi()*transmisivity /(self.Ln(inf_radius/observation_distance) ) )

    def observation_distance_unconfined(self, Ho, flow_rate, hydraulic_cond, dropdown, inf_radius):
        """
        Calculo de radio de observacion en acuíferos libres

            :Parameters:
                Ho : float
                  Altura inicial ( en este ejemplo en m).
                flow_rate : float
                  Caudal de extraccion (por ejemplo en m3/h).
                hydraulic_conductivity : float
                  Conductividad Hidraulica (por ejemplo en m/d).
                dropdown : float
                  Descenso en unidades homogeneas ( en este ejemplo en m).
                inf_radius : float
                  Radio de influencia..

            :rtype: float
            :return: Observation Distance in unconfined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.observation_distance_unconfined(10.0,250.0,6.0,3.0,800.0)
            >>> print ("%.3f" % dd )
            0.366
        """
        h = (Ho-dropdown)
        return (inf_radius/(self.exp((2*self.pi()*hydraulic_cond*(Ho*Ho-h*h))/flow_rate)))

    def aux_fun_ods(self,x,kk_0,B):
        """
        Auxiliar function to calculate observation_distance_semiconfined
        """
        return (self.k0(x/B) - kk_0)

    def observation_distance_semiconfined(self, well_radius, dropdown, flow_rate, transmisivity, B, kp=None,  bp=None):
        """
        Calculo de radio de observacion en acuíferos semiconfinados

            :Parameters:
                well_radius : float
                  Radio de influencia.
                dropdown : float
                  Descenso en unidades homogeneas ( en este ejemplo en m).
                flow_rate : float
                  Caudal de extraccion (por ejemplo en m3/h).
                transmisivity : float
                  Transmisividad hidraulica en unidades homogeneas ( en este ejemplo en m2/h).
                B : float
                  Factor Goteo ( en este ejemplo en m).

            :rtype: float
            :return: Observation Distance in semiconfined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.observation_distance_semiconfined(10.0,250.0,6.0,3.0,800.0)
            >>> print ("%.3f" % dd )
            0.366
        """
        # Initial observation distance (meters)
        kk_0 = 2*self.pi()*transmisivity*dropdown/flow_rate*well_radius/B*self.k1(well_radius/B)
        obs_i = 0.005 # diameter = 1 cm !!!!
        # root calculation using fsolve
        obs_calc = fsolve(self.aux_fun_ods,obs_i,args=(kk_0,B))
        return ( obs_calc )

    def observation_distance_confined(self, flow_rate, transmisivity,  drop_down,  inf_radius):
        """
        Calculo de radio de observacion en acuíferos confinados

            :Parameters:
                flow_rate : float
                  Caudal de extraccion (por ejemplo en m3/h).
                transmisivity : float
                  Transmisividad hidraulica en unidades homogeneas ( en este ejemplo en m2/h).
                dropdown : float
                  Descenso en unidades homogeneas ( en este ejemplo en m).
                inf_radius : float
                  Radio de influencia.

            :rtype: float
            :return: Observation Distance in confined aquifer

        **Usage**

            >>> import libs.hydrogeo.vwellpr
            >>> vwpr =  VWellPR()
            >>> dd = vwpr.observation_distance_confined(250.0,100.0,1.0,800.0)
            >>> print ("%.3f" % dd )
            5.249
        """
        return (inf_radius/self.exp((4*self.pi()*transmisivity*drop_down)/flow_rate))
